/***************************************************************
*
*		Program "p3.c" predstavlja primere koriscenja funkcija 
*		biblioteke "stdl.a", koja obesbjedjuje funkcije za
*		standardni ulaz i standardni izlaz celih brojeva, izlaz
*		stringova, kao i API za rad sa binarnim fajlovima.
*
***************************************************************/

#include "stdl.h"		

#define PMT_ENTRY_CNT		0x1000
#define PMT_SECTION			0x402
#define PMT_USER				0xC02
#define	BLOCK_SIZE			512
#define MB 							0x100000

extern unsigned int* PMT;

typedef struct {
		unsigned int vAddr;												//virtualena adresa
		unsigned int ptrAddr;											//adresa u fajlu
} pmtEntry;

pmtEntry pageTable[6];
unsigned int fileSize, nextPage;						
FILE disk;

void init()
{
	unsigned int i, vaddr;
	
	//writes("Inicijalizacija sistema");
	
	for(i=0,vaddr=0xA01; i<6; i++, vaddr++)
	{
		pageTable[i].vAddr = vaddr;
		pageTable[i].ptrAddr = 0;
	}
	fileSize = 0;
	nextPage = 0;
	
	disk = fcreate("disk.bin");
}

void processPageMissing(unsigned int va)
{
		
		unsigned int newptraddr = va / MB;
		
		if(pageTable[nextPage].ptrAddr != 0)				//ako postoji vec neka stranica i trebamo je izbaciti
		{
				unsigned int oldptraddr = pageTable[nextPage].ptrAddr;
				PMT[oldptraddr] = 0;
				
				writes("Izbachen ulaz iz memorije:");
				writel(oldptraddr);
		}	
		
		pageTable[nextPage].ptrAddr = newptraddr;
		
		//popunjavanje PMT tabele
		{
			unsigned long newva = ((pageTable[nextPage].vAddr & 0xFFF) << 20) + PMT_USER;
			PMT[newptraddr] = newva;
			
			writes("Upisan ulaz u PMT:");
			writel(newva);
			writel(newptraddr);
		}
				
		//kopiranje fajla u RAM
		{
				char s[BLOCK_SIZE];
				unsigned int i;
				char* ptr = (char*) ((pageTable[nextPage].vAddr & 0xFFF) << 20);
				
				fseek(disk, newptraddr-1);
				fread(disk,BLOCK_SIZE,s);
				
				for(i = 0; i < BLOCK_SIZE; i++)
						ptr[i] = s[i];
				
				writes("Kopirana stranica u RAM");
		}
		
		nextPage = ++nextPage % 6;
}

void clearPMT()
{
		unsigned int i;
		for(i=1; i<=fileSize; i++)
				PMT[i] = PMT_SECTION;
		
		for(i=0; i<6; i++)
		{
			pageTable[i].ptrAddr = 0;
		}
		nextPage = 0;
}

void printInfoDataAbort()
{
		writes("====Interupt - Data====");
}

void printInfoPrefetchAbort()
{
		writes("====Interupt - Prefetch====");
}

unsigned int processAbortInterrupt(unsigned int va)
{	
	writes("Dogodio se abort na adresi:");
	writel(va);														

	
	if(va < MB || va > fileSize*MB)
	{		
		writes("===Kraj programa===\n");
		clearPMT();
		return 0;
	}
		
	processPageMissing(va);
	
	return 1;
}

void main()
{	
	char s[BLOCK_SIZE];
	char userfilename[255];
	FILE userfile;
	unsigned int count;
	unsigned int i,vaddr;
	
	writes("====Pochetak programa====\n");
	
	writes("Unesite ime fajla za izvrshavanje: \0");
	while(1)
	{	
		reads(userfilename);
		if((userfile = fopen(userfilename)) !=0 )
			break;
		writes("Fajl ne postoji u tekucem direktorijumu.\nUnesite ponovo:");
	}
	writes("Otvoren fajl");
	writes(userfilename);
	writel(userfile);
	fileSize = 0;
	fseek(disk,0);
	writes("Prepisivanje fajla na disk");
	while(count = fread(userfile,BLOCK_SIZE,s))
	{
		fwrite(disk,count,s);
		fileSize++;
		fseek(userfile,fileSize*MB);
		fseek(disk,fileSize*MB);
	}
	
	writes("Velichina uchitanog fajla u MB: \0");
	writeb(fileSize);
	
	fclose(userfile);
	
	//postavljanje ulaza u PMT tabelu
	{
		unsigned i;
		for(i=1; i<=fileSize; i++)
			PMT[i] = 0;
	}
}



